package com.fsserver.web.controller;

import com.fsserver.common.api.ApiResponse;
import com.fsserver.core.dto.RefundRequestDTO;
import com.fsserver.core.entity.Refund;
import com.fsserver.core.service.RefundService;
import com.fsserver.core.service.WechatPayService;
import com.fsserver.core.service.AlipayService;
import com.fsserver.core.vo.RefundResponseVO;
import com.fsserver.core.vo.RequestNotification;
import com.fsserver.common.api.ResultCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 退款控制器
 * Refund Controller
 *
 * @author fsserver
 */
@Slf4j
@RestController
@RequestMapping("/refund")
@Api(tags = "退款管理接口", description = "提供退款创建、查询等功能")
public class RefundController {

    @Autowired
    private RefundService refundService;
    
    @Autowired
    private WechatPayService wechatPayService;
    
    @Autowired
    private AlipayService alipayService;

    /**
     * 创建退款
     * Create refund
     *
     * @param refundRequestDTO 退款请求DTO
     * @param request HTTP请求
     * @return API响应
     */
    @PostMapping
    @ApiOperation(value = "创建退款", notes = "根据退款请求DTO创建退款")
    public ApiResponse<RefundResponseVO> createRefund(@Valid @RequestBody RefundRequestDTO refundRequestDTO, HttpServletRequest request) {
        refundRequestDTO.setUserIp(getClientIp(request));
        RefundResponseVO refundResponseVO = refundService.createRefund(refundRequestDTO);
        return ApiResponse.success(refundResponseVO);
    }

    /**
     * 查询退款
     * Query refund
     *
     * @param refundNo 退款号
     * @return API响应
     */
    @GetMapping("/{refundNo}")
    @ApiOperation(value = "查询退款", notes = "根据退款号查询退款")
    @ApiImplicitParam(name = "refundNo", value = "退款号", required = true, dataType = "String", paramType = "path")
    public ApiResponse<Refund> queryRefund(@PathVariable String refundNo) {
        Refund refund = refundService.queryRefund(refundNo);
        return ApiResponse.success(refund);
    }

    /**
     * 根据订单号查询退款列表
     * List refunds by order number
     *
     * @param orderNo 订单号
     * @return API响应
     */
    @GetMapping("/order/{orderNo}")
    @ApiOperation(value = "根据订单号查询退款列表", notes = "根据订单号查询退款列表")
    @ApiImplicitParam(name = "orderNo", value = "订单号", required = true, dataType = "String", paramType = "path")
    public ApiResponse<List<Refund>> listRefundsByOrderNo(@PathVariable String orderNo) {
        List<Refund> refunds = refundService.listRefundsByOrderNo(orderNo);
        return ApiResponse.success(refunds);
    }

    /**
     * 根据交易号查询退款列表
     * List refunds by transaction number
     *
     * @param transactionNo 交易号
     * @return API响应
     */
    @GetMapping("/transaction/{transactionNo}")
    @ApiOperation(value = "根据交易号查询退款列表", notes = "根据交易号查询退款列表")
    @ApiImplicitParam(name = "transactionNo", value = "交易号", required = true, dataType = "String", paramType = "path")
    public ApiResponse<List<Refund>> listRefundsByTransactionNo(@PathVariable String transactionNo) {
        List<Refund> refunds = refundService.listRefundsByTransactionNo(transactionNo);
        return ApiResponse.success(refunds);
    }
    
    /**
     * 微信退款
     * WeChat Refund
     *
     * @param orderNo 订单号
     * @param refundNo 退款单号
     * @param totalAmount 订单总金额（单位：分）
     * @param refundAmount 退款金额（单位：分）
     * @param reason 退款原因
     * @return API响应
     */
    @PostMapping("/wechat")
    @ApiOperation(value = "微信退款", notes = "申请微信支付退款")
    public ApiResponse<Map<String, Object>> wechatRefund(
            @RequestParam String orderNo,
            @RequestParam String refundNo,
            @RequestParam Long totalAmount,
            @RequestParam Long refundAmount,
            @RequestParam String reason) {
        Map<String, Object> result = wechatPayService.refund(orderNo, refundNo, totalAmount, refundAmount, reason);
        return ApiResponse.success(result);
    }

    /**
     * 查询微信退款
     * Query WeChat Refund
     *
     * @param refundNo 退款单号
     * @return API响应
     */
    @GetMapping("/wechat/{refundNo}")
    @ApiOperation(value = "查询微信退款", notes = "查询微信退款状态")
    @ApiImplicitParam(name = "refundNo", value = "退款单号", required = true, dataType = "String", paramType = "path")
    public ApiResponse<Map<String, Object>> queryWechatRefund(@PathVariable String refundNo) {
        Map<String, Object> result = wechatPayService.queryRefund(refundNo);
        return ApiResponse.success(result);
    }

    /**
     * 处理退款通知
     * Handle refund notification
     *
     * @param paymentType 支付类型
     * @param request HTTP请求
     * @return 处理结果
     */
    @PostMapping("/notify/{paymentType}")
    @ApiOperation(value = "处理退款通知", notes = "处理退款通知回调")
    @ApiImplicitParam(name = "paymentType", value = "支付类型", required = true, dataType = "String", paramType = "path")
    public String handleRefundNotification(@PathVariable String paymentType, HttpServletRequest request) {
        Map<String, String> params = getRequestParams(request);
        boolean result = refundService.handleRefundNotification(paymentType, params);
        return result ? "success" : "fail";
    }

    /**
     * 处理微信退款通知
     * Handle WeChat Refund Notification
     *
     * @param request HTTP请求
     * @return 处理结果
     */
    @PostMapping("/wechat/notify")
    @ApiOperation(value = "处理微信退款通知", notes = "处理微信退款结果通知")
    public String handleWechatRefundNotification(HttpServletRequest request) {
        try {
            // 构建通知对象
            RequestNotification notification = buildNotification(request, "WECHAT");
            boolean result = wechatPayService.handleRefundNotification(notification);
            return result ? "SUCCESS" : "FAIL";
        } catch (Exception e) {
            log.error("处理微信退款通知失败", e);
            return "FAIL";
        }
    }

    /**
     * 构建通知对象
     * 
     * @param request HTTP请求
     * @param paymentType 支付类型
     * @return 通知对象
     * @throws Exception 异常
     */
    private RequestNotification buildNotification(HttpServletRequest request, String paymentType) throws Exception {
        RequestNotification notification = new RequestNotification();
        notification.setPaymentType(paymentType);
        notification.setRequestId(request.getHeader("Request-ID"));
        
        // 读取请求体
        StringBuilder sb = new StringBuilder();
        try (java.io.BufferedReader reader = request.getReader()) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        }
        notification.setBody(sb.toString());
        
        // 获取所有请求头
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            headers.put(name, request.getHeader(name));
        }
        notification.setHeaders(headers);
        
        // 获取所有请求参数
        notification.setParameters(getRequestParams(request));
        
        return notification;
    }

    /**
     * Get client IP
     *
     * @param request HTTP request
     * @return client IP
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * Get request parameters
     *
     * @param request HTTP request
     * @return request parameters
     */
    private Map<String, String> getRequestParams(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String name = parameterNames.nextElement();
            String value = request.getParameter(name);
            params.put(name, value);
        }
        return params;
    }

    /**
     * 申请支付宝退款
     *
     * @param refundRequestDTO 退款请求DTO
     * @return API响应
     */
    @PostMapping("/alipay/apply")
    @ApiOperation(value = "申请支付宝退款", notes = "申请支付宝订单退款")
    public ApiResponse<Map<String, Object>> alipayRefund(@Valid @RequestBody RefundRequestDTO refundRequestDTO) {
        // 参数校验
        String orderNo = refundRequestDTO.getOrderNo();
        String refundNo = refundRequestDTO.getRefundNo();
        BigDecimal refundAmount = refundRequestDTO.getAmount();
        BigDecimal totalAmount = refundRequestDTO.getTotalAmount();
        String reason = refundRequestDTO.getReason();

        if (StringUtils.isEmpty(orderNo)) {
            return ApiResponse.error(ResultCode.PARAM_ERROR, "订单号不能为空");
        }
        if (StringUtils.isEmpty(refundNo)) {
            return ApiResponse.error(ResultCode.PARAM_ERROR, "退款单号不能为空");
        }
        if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return ApiResponse.error(ResultCode.PARAM_ERROR, "退款金额必须大于0");
        }
        if (totalAmount == null || totalAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return ApiResponse.error(ResultCode.PARAM_ERROR, "订单总金额必须大于0");
        }

        try {
            // 调用支付宝退款接口
            Map<String, Object> result = alipayService.refund(
                orderNo, 
                refundNo, 
                totalAmount.multiply(new BigDecimal("100")).longValue(), 
                refundAmount.multiply(new BigDecimal("100")).longValue(), 
                reason
            );
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("申请支付宝退款失败", e);
            return ApiResponse.error(ResultCode.SYSTEM_ERROR, "申请退款失败: " + e.getMessage());
        }
    }

    /**
     * 查询支付宝退款
     *
     * @param refundNo 退款单号
     * @return API响应
     */
    @GetMapping("/alipay/query/{refundNo}")
    @ApiOperation(value = "查询支付宝退款", notes = "查询支付宝退款状态")
    @ApiImplicitParam(name = "refundNo", value = "退款单号", required = true, dataType = "String", paramType = "path")
    public ApiResponse<Map<String, Object>> queryAlipayRefund(@PathVariable String refundNo) {
        if (StringUtils.isEmpty(refundNo)) {
            return ApiResponse.error(ResultCode.PARAM_ERROR, "退款单号不能为空");
        }

        try {
            // 调用支付宝退款查询接口
            Map<String, Object> result = alipayService.queryRefund(refundNo);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("查询支付宝退款失败", e);
            return ApiResponse.error(ResultCode.SYSTEM_ERROR, "查询退款失败: " + e.getMessage());
        }
    }
} 